package engine.utils
{
	import engine.classes.display.BitmapCreator;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.display.PixelSnapping;
	import flash.display.Sprite;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class DisplayUtils
	{
		private static const POINT:Point = new Point();
		
		/**
		 * Moves a Display Object to the front of its parent's display list.
		 */
		public static function toFront(display:DisplayObject):void
		{
			if(display.parent) display.parent.setChildIndex(display, display.parent.numChildren - 1);
		}
		
		/**
		 * Moves a Display Object to the back of its parent's display list.
		 */
		public static function toBack(display:DisplayObject):void
		{
			if(display.parent) display.parent.setChildIndex(display, 0);
		}
		
		/**
		 * Removes the <code>current</code> Display Object from its parent and adds the <code>next</code>
		 * Display Object to its parent at the same index.
		 */
		public static function swapChild(current:DisplayObject, next:DisplayObject):void
		{
			if(!current) 	throw new Error("DisplayUtils :: swapChild() :: DisplayObject <" + current.name + "> is null.");
			if(!next) 		throw new Error("DisplayUtils :: swapChild() :: DisplayObject <" + next.name + "> is null.");
			
			trace(current.name);
			var parent:DisplayObjectContainer = current.parent;
			if(parent)
			{
				var index:int = parent.getChildIndex(current);
				
				parent.removeChildAt(index);
				parent.addChildAt(next, index);
				
				if(parent is MovieClip) parent[current.name] = next;
			}
		}
		
		public static function setIndex(display:DisplayObject, container:DisplayObjectContainer = null, index:int = -1):void
		{
			if(!container) return;
			
			if(index == -1) index = container.numChildren;
			else if(index > container.numChildren - 1) index = container.numChildren - 1;
			
			container.addChildAt(display, index);
		}
		
		/**
		 * Removes a Display Object from its parent into a new parent and maintains its visual
		 * positioning on-screen. This changes the Display Object's x and y in its new container.
		 */
		public static function swapParent(display:DisplayObject, parent:DisplayObjectContainer, index:int = -1):void
		{
			if(!display.parent) return;
			
			var point:Point = DisplayUtils.localToLocal(display.x, display.y, display.parent, parent);
			
			if(index == -1) index = parent.numChildren;
			parent.addChildAt(display, index);
			
			display.x = point.x;
			display.y = point.y;
		}
		
		/**
		 * Converts an (x, y) Point in the <code>current</code> Display Object's local space to a Point in
		 * the <code>next</code> Display Object's local space. 
		 */
		public static function localToLocal(x:Number, y:Number, current:DisplayObject, next:DisplayObject):Point
		{
			POINT.setTo(x, y);
			return next.globalToLocal(current.localToGlobal(POINT));
		}
		
		/**
		 * Helper function that properly disposes of a Display Object and iterates through its children
		 * to dispose of them as well.
		 */
		public static function destroy(display:DisplayObject):void
		{
			if(display.parent) display.parent.removeChild(display);
			
			if(display is Bitmap)
			{
				with(display)
				{
					bitmapData.dispose();
					bitmapData = null;
				}
			}
			else if(display is DisplayObjectContainer)
			{
				if(display is MovieClip) MovieClip(display).stop();
				
				var container:DisplayObjectContainer = display as DisplayObjectContainer;
				while(container.numChildren > 0)
				{
					var child:DisplayObject = container.getChildAt(0);
					DisplayUtils.destroy(child);
				}
				container = null;
			}
		}
		
		/**
		 * Helper function to trace() out the display list order and names of each Display Object in the list.
		 */
		public static function traceContainers(container:DisplayObjectContainer):void
		{
			for(var i:int = 0; i < container.numChildren; i++)
			{
				var child:DisplayObject = container.getChildAt(i);
				
				var name:String = child.name;
				var parent:DisplayObjectContainer = child.parent;
				while(parent)
				{
					name = parent.name + "->" + name;
					parent = parent.parent;
				}
				trace(name);
				
				if(child is DisplayObjectContainer)
					traceContainers(child as DisplayObjectContainer);
			}
		}
	}
}